#pragma once

#include <vector>

#ifdef PUNCH_MSGPACK
#include <msgpack.hpp>
#endif

namespace mdtx::punch::tradesim
{
    /**
     * @brief Records client funds
     *
     * @tparam QT quote type
     */
    template <typename QT>
    class Funds
    {
    public:
        using id_type = typename QT::id_type;
        using quant_type = typename QT::quant_type;

        struct FundsT
        {
            quant_type net0, net, avail, borrow0, borrow;

#ifdef PUNCH_MSGPACK
            MSGPACK_DEFINE_ARRAY(net0, net, avail, borrow0, borrow);
#endif
        };

        static auto create(quant_type cash)
        {
            if (cash < 0)
            {
                return FundsT{cash, cash, quant_type{}, -cash, -cash};
            }
            else
            {
                return FundsT{cash, cash, cash, quant_type{}, quant_type{}};
            }
        }

    private:
        size_t n_cli;
        std::vector<FundsT> val;

    public:
        explicit Funds(size_t n_cli)
            : n_cli(n_cli), val(n_cli, FundsT{})
        {
        }

        size_t num_client() const { return n_cli; }

        auto &get(id_type cli_id) { return val[cli_id]; }
        const auto &get(id_type cli_id) const { return val[cli_id]; }

        template <class ItQuant>
        void set(ItQuant cash)
        {
            for (size_t idx = 0; idx < n_cli; ++idx)
            {
                val[idx] = create(*cash++);
            }
        }

        void set(id_type cli_id, quant_type cash)
        {
            val[cli_id] = create(cash);
        }

        id_type new_client()
        {
            val.push_back(create(quant_type{}));
            return n_cli++;
        }

        id_type new_client(quant_type cash)
        {
            val.push_back(create(cash));
            return n_cli++;
        }
    };
}
